package main

import (
	"flag"
	"gitee.com/sunny-zhangqiang/zcache/comm/lockfile"
	"gitee.com/sunny-zhangqiang/zcache/config"
	"gitee.com/sunny-zhangqiang/zcache/logger"
	"gitee.com/sunny-zhangqiang/zcache/service"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var cFlag = flag.String("c", "", "Set configuration file path")
var clearCacheFlag = flag.Bool("clear_cache", false, "Clear cache and exit the service")
var createNewFlag = flag.Bool("create_new", false, "Clear cache and run service")

func errorLogInit() {
	if !config.ServerConf.EnableErrLog {
		return
	}
	scrollingMode := logger.ScrollingNone
	switch config.ServerConf.ErrLogScrollingMode {
	case "none":
		scrollingMode = logger.ScrollingNone
	case "minute":
		scrollingMode = logger.ScrollingMinMode
	case "hour":
		scrollingMode = logger.ScrollingHourMode
	case "day":
		scrollingMode = logger.ScrollingDayMode
	default:
		logger.SysError("invalid error log scrolling mode")
		os.Exit(1)
	}

	fileOutput, err := logger.NewFileOutputAsync(config.ServerConf.ErrLogPath,
		scrollingMode, true, 5, 0, 4)
	if err != nil {
		logger.SysError("create error log outpute failed")
		os.Exit(1)
	}

	logLever := logger.ErrorLevel

	switch config.ServerConf.ErrLogLevel {
	case "debug":
		logLever = logger.DebugLevel
	case "warn":
		logLever = logger.WarnLevel
	case "error":
		logLever = logger.ErrorLevel
	default:
		logger.SysError("invalid error log lever")
		os.Exit(1)
	}

	logger.SetLevel(logLever)
	// clear stdOutput
	logger.ClearOutputs()
	logger.AddOutput(fileOutput)
}

func main() {
	flag.Parse()

	createNew := false
	if *clearCacheFlag || *createNewFlag {
		createNew = true
	}

	if *cFlag == "" {
		logger.SysError("Please set configuration file path")
		os.Exit(1)
	}

	err := config.LoadServerConf(*cFlag)
	if err != nil {
		logger.SysError("Parse config failed, err: %s", err.Error())
		os.Exit(1)
	}

	fl, err := lockfile.New(config.ServerConf.LockFilePath)
	if err != nil {
		logger.SysError("create file lock failed")
		os.Exit(1)
	}

	err = fl.Lock(false)
	if err != nil {
		logger.SysError("lock file lock failed")
		os.Exit(1)
	}

	errorLogInit()

	err = service.AccessLogInit()
	if err != nil {
		logger.SysError("access log init failed, err: %s", err)
		os.Exit(1)
	}

	err = service.OpenCache(createNew)
	if err != nil {
		logger.SysError("access log init failed")
		os.Exit(1)
	}

	if *clearCacheFlag {
		logger.SysDebug("clear cache success")
		service.CloseCache()
		return
	}

	err = service.Start()
	if err != nil {
		logger.SysError("service start failed, err: %s", err.Error())
		os.Exit(1)
	}

	logger.SysDebug("service start success")

	// quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGQUIT)

	for s := range c {
		if s == syscall.SIGQUIT {
			break
		}
	}

	timer := time.NewTimer(time.Duration(config.ServerConf.QuitTimeoutSec+1) * time.Second)

	quitC := make(chan struct{})
	go func() {
		service.NotifyStop()
		service.CloseCache()
		service.WaitStop()
		quitC <- struct{}{}
	}()

	select {
	case <-timer.C:
		logger.SysDebug("quit timeout, force exit")
		os.Exit(0)
		return
	case <-quitC:
		logger.SysDebug("quit success")
		os.Exit(0)
		return
	}
}
